package br.unifor.ia;

import java.util.logging.Level;
import java.util.logging.Logger;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 * Classe Abstrata para representar um agente.
 * @author pedro
 */
public abstract class Agente extends Thread {
    
    /**
     * Indica se o agente soltou uma flecha na esperança de matar o monstro.
     */
     private boolean soltouFlecha;
    /**
     * Direção do personagem.
     */
    private int direcao;
    /**
     * Indica se o peronagem achou o ouro.
     */
    private boolean achouOuro;
    /**
     * Indica a posicação x,y do personagem na matriz.
     */
    private Posicao pos;
    /**
     * Representa o sensor do personagem.
     */
    private int sensor;
    /**
     * Existe um modo de teste, quando alguma tecla é apertada essa variável é setada pra true 
     * para que o agente seja desabilitado e a direção do personagem seja setada pelo usuário
     * através do direcional do teclado.
     */
    private boolean modoTeste;
    /**
     * Representa a direção para cima do personagem.
     */
    public static final int AGENT_UP = 0;
    /**
     * Representa a direção para baixo do personagem.
     */
    public static final int AGENT_DOWN = 1;
    /**
     * Representa a direção para esquerda do personagem.
     */
    public static final int AGENT_LEFT = 2;
    /**
     * Representa a direção para direita do personagem.
     */
    public static final int AGENT_RIGHT = 3;
    /**
     * Representa que o jogo foi encerrado com o sinal de gameover.
     */
    private boolean gameOver;
    /**
     * Representa a situação de o personagem ter sido 'sugado' pelo buraco ou pela saída.
     */
    private boolean sugado;
    /**
     * Representa a situação que o usuário achou o ouro e saiu do ambiente com sucesso.
     */
    private boolean venceu;

    /**
     * Método onde vai ficar toda a programação do agente.
     */
    protected abstract void acao();

    @Override
    public void run() {
        while (!gameOver&&!venceu) {
            try {
                perceber();
                if (!isModoTeste()) {
                    acao();
                }
                System.out.println("Posição do personagem " + "[" + getPos().getX() + "][" + getPos().getY() + "]");
                Thread.sleep(Constantes.TEMPO_THREAD_AGENT);
            } catch (InterruptedException ex) {
                Logger.getLogger(Agente.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public int getDirecao() {
        return direcao;
    }

    public void setDirecao(int direcao) {
        this.direcao = direcao;
    }

    public boolean isAchouOuro() {
        return achouOuro;
    }

    public void setAchouOuro(boolean achouOuro) {
        this.achouOuro = achouOuro;
    }

    /**
     * Retorna a posição do agente na matriz.
     * @return pos.
     */
    public Posicao getPos() {
        if (pos == null) {
            pos = new Posicao(2, 21);
        }
        return pos;
    }

    public void setPos(Posicao pos) {
        this.pos = pos;
    }

    public int getSensor() {
        return sensor;
    }

    public void setSensor(int sensor) {
        this.sensor = sensor;
    }

    /**
     * Mostra sysout no log das permissões do agente, e acompanha os estados do jogo.
     */
    private void perceber() {
        switch (getSensor()) {
            case Ambiente.SIMB_BRILHO_OURO: {
                System.out.println("Brilho do ouro!");
                break;
            }
            case Ambiente.SIMB_BRISA_BURACO: {
                System.out.println("Brisa!");
                break;
            }
            case Ambiente.SIMB_BURACO: {
                System.out.println("Buraco!");
                sugado = true;
                gameOver = true;
                break;
            }
            case Ambiente.SIMB_FEDOR_WUMPUS: {
                System.out.println("Fedor!");
                break;
            }
            case Ambiente.SIMB_OURO: {
                System.out.println("Ouro!");
                achouOuro = true;
                break;
            }
            case Ambiente.SIMB_WUMPUS: {
                System.out.println("Wumpus!");
                gameOver = true;
                break;
            }
            case Ambiente.SIMB_ENTRADA_SAIDA: {
                System.out.println("Entrada / Saída");
                if (isAchouOuro()) {
                    sugado = true;
                    venceu = true;
                }
                break;
            }
        }
    }

    public boolean isModoTeste() {
        return modoTeste;
    }

    public void setModoTeste(boolean modoTeste) {
        this.modoTeste = modoTeste;
    }

    /**
     * Método que seta a direção do personagem para a direção oposta da direção corrente.
     */
    public void voltar() {
        switch (getDirecao()) {
            case Agente.AGENT_UP: {
                setDirecao(Agente.AGENT_DOWN);
                break;
            }
            case Agente.AGENT_DOWN: {
                setDirecao(Agente.AGENT_UP);
                break;
            }
            case Agente.AGENT_LEFT: {
                setDirecao(Agente.AGENT_RIGHT);
                break;
            }
            case Agente.AGENT_RIGHT: {
                setDirecao(Agente.AGENT_LEFT);
                break;
            }
        }
    }

    public boolean isGameOver() {
        return gameOver;
    }

    public void setGameOver(boolean gameOver) {
        this.gameOver = gameOver;
    }

    public boolean isSugado() {
        return sugado;
    }

    public void setSugado(boolean sugado) {
        this.sugado = sugado;
    }

    public boolean isVenceu() {
        return venceu;
    }

    public void setVenceu(boolean venceu) {
        this.venceu = venceu;
    }

    public boolean isSoltouFlecha() {
        return soltouFlecha;
    }

    public void setSoltouFlecha(boolean soltouFlecha) {
        this.soltouFlecha = soltouFlecha;
    }
}
